import threading
import datetime
from typing import List, Dict, Any, Optional



from database.milvus_client import MilvusClient
from pymilvus import (
    FieldSchema,
    DataType
)

import logging
from models.chat_record import ChatRecord, ContentType, Role
from utils.aes_util import AES256Cipher

# from utils.aes_util import aes_encrypt,aes_decrypt

logger = logging.getLogger(__name__)



class ChatRecordServer(MilvusClient):
    _instance = None
    _lock = threading.Lock()
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            with cls._lock:
                if not cls._instance:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self,host:str = "localhost",port: str = "19530", user:str="root",pwd:str="szsk8888"):
        #数据库集合名字
        password="szsk"
        salt = b'fixed_salt_12345'
        self.cipher1 = AES256Cipher(password,salt=salt)
        self.collection_name="chat_records_s_0615test_3"
        self.collection_fields=[
            FieldSchema(name="id", dtype=DataType.VARCHAR, is_primary=True, max_length=36),
            FieldSchema(name="user_id", dtype=DataType.VARCHAR, max_length=36),
            FieldSchema(name="saas_id", dtype=DataType.VARCHAR, max_length=36),
            FieldSchema(name="content_type", dtype=DataType.VARCHAR, max_length=20, default_value="text"),
            FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=5000, default_value=""),

            FieldSchema(name="role", dtype=DataType.VARCHAR, max_length=20, default_value="user"),
            FieldSchema(name="content_des", dtype=DataType.VARCHAR, max_length=1000, default_value=""),
            FieldSchema(name="timestamp", dtype=DataType.VARCHAR, max_length=64, default_value=""),
            FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=2560),
            FieldSchema(name="chat_embedding", dtype=DataType.FLOAT_VECTOR, dim=2560)
        ]

        super().__init__(host=host, port=port,collection_name=self.collection_name,fields=self.collection_fields,user=user,pwd=pwd)

    def create_index(self):
        """创建向量索引"""
        index_params = {
            "metric_type": "L2",
            "index_type": "IVF_FLAT",
            "params": {"nlist": 128}
        }

        self.collection.create_index(
            field_name="embedding",
            index_params=index_params
        )
        logger.info("已创建向量索引")

        self.collection.create_index(
            field_name="chat_embedding",
            index_params=index_params
        )
        logger.info("已创建向量索引")



    def insert_record(self, record: ChatRecord, embedding: list,chat_embedding: list) -> str:
        """插入新记录"""
        try:
             # 使用新方法名
            record.timestamp=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            conten=self.cipher1.encrypt (record.content)
            data = [
                [record.id],
                [record.user_id],
                [record.saas_id],
                [record.content_type.value],
                [conten],
                [record.role.value],
                [record.content_des] if record.content_des else [None],
                [record.timestamp],
                [embedding],
                [chat_embedding]
            ]
            print("开始："+datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            mr = self.collection.insert(data)
            # self.collection.flush()
            print("结束：" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            logger.debug(f"已插入记录: {record.id}")
            return record.id
        except Exception as e:
            logger.error(f"插入记录失败: {str(e)}")
            raise RuntimeError(f"插入记录失败: {str(e)}") from e



    def search_records(
            self,
            saas_id:str,
            user_id: str,
            query_embedding: list,
            content_type: Optional[ContentType] = None,
            role: Optional[Role] = None,
            top_k: int = 1,
            alpha = 0.4,
            min_score=1
    ) -> List[Dict[str, Any]]:
        search_params = {
            "metric_type": "L2",
            "params": {"nprobe": 16}
        }

        # 构建查询表达式
        expr_parts = [f'user_id == "{user_id}"']
        expr_parts.append(f'saas_id == "{saas_id}"')

        if content_type:
            expr_parts.append(f'content_type == "{content_type.value}"')

        if role:
            expr_parts.append(f'role == "{role.value}"')

        expr = " and ".join(expr_parts)

        results1 = self.collection.search(
            data=[query_embedding],
            anns_field="chat_embedding",
            param=search_params,
            limit=top_k,
            expr=expr,
            output_fields=["content_type", "content", "role", "content_des", "timestamp"]
        )
        results2 = self.collection.search(
            data=[query_embedding],
            anns_field="embedding",
            param=search_params,
            limit=top_k,
            expr=expr,
            output_fields=["content_type", "content", "role", "content_des", "timestamp"]
        )

        fused_results = []

        # for hits in results1:
        #     for hit in hits:
        #         print(f"results1_score；{hit.score}")
        #         fused_results.append({
        #             "id": hit.id,
        #             "score": hit.score * alpha,
        #             "type": "text",
        #             **{k: hit.entity.get(k) for k in ["content","content_des"]}
        #         })
        #
        # for hits in results2:
        #     for hit in hits:
        #         print(f"results2_score；{hit.score}")
        #         fused_results.append({
        #             "id": hit.id,
        #             "score": hit.score * (1 - alpha),  # 图像分数加权
        #             "type": "text",
        #             **{k: hit.entity.get(k) for k in ["content","content_des"]}
        #         })
        for hits in results1:
            for hit in hits:
                if hit.score > min_score:
                    continue
                c = hit.entity.get('content')
                resc = self.cipher1.decrypt(c)
                fused_results.append({
                    "content_type": hit.entity.get('content_type'),
                    "content": resc,
                    "role": hit.entity.get('role'),
                    "content_des": hit.entity.get('content_des'),
                    "timestamp": hit.entity.get('timestamp'),
                    "score": hit.score * alpha,
                })
        for hits in results2:
            for hit in hits:
                if hit.score > min_score:
                    continue
                c = hit.entity.get('content')
                resc = self.cipher1.decrypt(c)
                fused_results.append({
                    "content_type": hit.entity.get('content_type'),
                    "content": resc,
                    "role": hit.entity.get('role'),
                    "content_des": hit.entity.get('content_des'),
                    "timestamp": hit.entity.get('timestamp'),
                    "score": hit.score * (1 - alpha),
                })

        return sorted(fused_results, key=lambda x: -x["score"])[:top_k]













        # records = []
        # for hits in results:
        #     for hit in hits:
        #
        #         print(f"聊天1；{hit.score}")
        #         # if hit.score > 1.0:
        #         #     continue
        #         c=hit.entity.get('content')
        #         resc= self.cipher1.decrypt(c)
        #         records.append({
        #             "content_type": hit.entity.get('content_type'),
        #             "content": resc,
        #             "role": hit.entity.get('role'),
        #             "content_des": hit.entity.get('content_des'),
        #             "timestamp": hit.entity.get('timestamp')
        #         })
        #
        # return records